const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// const ReactRefreshWebpackPlugin = require('react-refresh-webpack-plugin');
const config = require('../public/config.json');
const getStyleLoaders = ( preProcessor) => {
    return [
        "style-loader",
        "css-loader",
        {
            loader: "postcss-loader",
            options: {
                postcssOptions: {
                    plugins: [
                        // 'autoprefixer',
                        'postcss-preset-env'// 能解决大多数样式兼容性问题
                    ],
                },
            },
        },
        preProcessor,
    ].filter(Boolean);
};
module.exports = {
    mode: 'development',
    entry: "./src/index.tsx",
    target: 'web',
    output: {
      path: undefined,
      filename: "script/js/[name].bundle.js",
      chunkFilename: "script/js/[name].chunk.js",
      assetModuleFilename: "script/media/[hash:10][ext][query]",
      clean: true,
    },
    optimization: {
      splitChunks: {
        chunks: "all",
      },
      runtimeChunk: {
        name: (entrypoint) => `runtime~${entrypoint.name}.js`,
      },
    },
    // 没有生成列映射(column mapping)，只是映射行数
    devtool: 'eval-cheap-source-map',
    module: {
        rules: [
            // {
            //     // 匹配一个就结束
            //     oneOf: [
                    /**
                     * cacheDirectory: 这个选项用于启用缓存机制。当true时，babel-loader会将转换后的文件缓存到一个指定的目录下。这样，下一次编译时，
                     * 如果文件没有改变，babel-loader可以直接从缓存中读取已经转换过的文件，而不是重新进行转换。这可以显著加快编译速度，特别是在大型项目中。
                     */
                    {
                        test: /\.(js|jsx|ts|tsx)$/, // 匹配 .js 和 .jsx .ts .tsx文件 
                        exclude: /node_modules/,
                        use: {
                            loader: 'babel-loader',
                            // Babel 会将转换后的文件缓存到 node_modules/.cache/babel-loader/ 目录中。
                            options: {
                                cacheDirectory: false, // 启用缓存
                            }
                        }
                    },
                    // less
                    /**
                     * * 1. style-loader: 将 JS 字符串生成为 style 节点 然后插入到创建style标签插到head下
                     * * 2. css-loader: 将 CSS 文件转换为 CommonJS 模块 将 css 解析成 js，但不能挂载到元素上
                     * * * 3. less-loader: 将 less 文件转换为 css 文件
                     * 使用CSS3的一些新特性时，需要为不同的浏览器在CSS代码中添加不同的前缀，在开发中手动添加太麻烦，
                     * 所以我们可以通过postcss来自动添加各种浏览器前缀。
                     * autoprefixer 用来添加浏览器前缀、 cssnano 用来压缩 CSS、
                     *  postcss-preset-env 用来根据目标浏览器生成 CSS的 polyfill
                     * 
                     * postcss-loader的option
                     * 旧版
                     * 
                     *  {
                            loader: 'postcss-loader',
                            options: {
                            plugins: [
                                require('autoprefixer'),
                                // 其他 PostCSS 插件
                            ],
                            },
                        },
                        要是想postcss-loader生成浏览器前缀配置还需要在package.json中
                        配置browserslist浏览器兼容性配置
                     */
                    // css
                    {
                        test: /\.css$/, use: getStyleLoaders()
                    },
                    {
                        test: /\.less$/, use: getStyleLoaders('less-loader')
                    },
                    // sass
                    {
                        test: /\.s[ac]ss$/i, use: getStyleLoaders('sass-loader')
                    },
                    // 静态资源
                    // { test: /\.(png|jpg|gif|svg|ico)$/, type: 'asset', generator: { filename: 'assets/[name][ext]' } } //传统
                    {                                       //配置图片静态资源的打包信息
                        test: /\.(jpg|png|jpeg|gif)$/,
                        use: [
                            {
                                loader: 'url-loader',
                                options: {
                                    limit: 1024,
                                    fallback: {
                                        loader: 'file-loader',
                                        options: {
                                            name: 'img/[name].[hash:8].[ext]'
                                        }
                                    }
                                }
                            }
                        ]
                    },
                    {                                       //配置多媒体资源的打包信息
                        test: /\.(mp4|webm|ogg|mp3|wav)$/,
                        use: [
                            {
                                loader: 'url-loader',
                                options: {
                                    limit: 1024,
                                    fallback: {
                                        loader: 'file-loader',
                                        options: {
                                            name: 'media/[name].[hash:8].[ext]'
                                        }
                                    }
                                }
                            }
                        ]
                    }
                ]
        //     }
        // ]
    },
    devServer: {
        // static: path.join(__dirname, 'dist'),//指定静态文件所在的目录。 // 替代 contentBase
        // publicPath: '/assets', // 静态文件在 URL 中的路径
        // serveIndex: true, // 启用目录索引
        // watch: true, // 启用文件变更监视
        // compress: true,//是否选择开启gzips压缩功能
        port: config.DEVSERVER_PORT || 3001,
        open: true,//是否自动打开浏览器
        hot: true, // 开启热更新
        historyApiFallback: true,// 在使用HTML5的历史记录API时，所有的404请求会被重定向到 /index.html
        proxy: [
            {
                context: ['/api'],
                target: 'http://localhost:3000',
                pathRewrite: { '^/api': '' },
            },
        ],
        // headers: { // 设置HTTP响应头
        //     'X-Custom-Foo': 'bar'
        // },
        client: {
            overlay: { // 在浏览器中全屏显示编译错误或警告
                warnings: true,
                errors: true
            },
            // 'info', 'warn', 'error', 'none', 'verbose'等
            logging: "info" // 控制台输出的日志级别 info
        },
        // stats: 'minimal', // 控制编译时在终端输出的内容  不支持
    },
    resolve: {
        // 简化模块导入的过程
        extensions: ['.ts', '.tsx', '.js', '.jsx'],
        alias: {
            pages: path.join(__dirname, '../src/pages'),
            layouts: path.join(__dirname, '../src/layouts'),
            components: path.join(__dirname, '../src/components'),
            actions: path.join(__dirname, '../src/redux/actions'),
            reducers: path.join(__dirname, '../src/redux/reducers'),
            images: path.join(__dirname, '../src/images'),
            utils: path.join(__dirname, '../src/utils'),
        }
    },
    plugins: [
        /**
         * webpack 构建过程支持类型检查
         *  async 标志来告诉 webpack 等待代码的类型检查结束，然后才提交代码进行编译
         */
        new ForkTsCheckerWebpackPlugin({
            async: false,
        }),
        new ESLintPlugin({
            extensions: ['js', 'jsx', 'ts', 'tsx'],//扩展名
            files: '../src/**/*.{js,jsx,ts,tsx}',//只检查这个目录下的扩展名为这些的文件
            // 不包括
            exclude: ['node_modules', 'dist', 'build'],
            cache: true,
            cacheLocation:path.resolve(__dirname, '../node_modules/.cache/.eslintcache'),
            /**
             * 这个参数指定了 ESLint 报告的结果格式。'table' 表示输出应该是表格形式的。ESLint 支持多种格式，这可以用来格式化输出结果，使报告更加清晰和易于阅读。
             */
            formatter: 'table'
        }),
        // 配置hot：true 无需手动添加
        // new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, "../public/index.html"),
            filename: 'index.html',
            // 压缩html资源  生产压缩 否则不压缩
            minify: false
        }),
        new webpack.DefinePlugin({
            SET_CONFIG_PATH: config
        })
    ],
}

